package model

import (
	"fmt"
	"context"
	"github.com/klen-ygs/gorm-zero/gormc"
	. "github.com/klen-ygs/gorm-zero/gormc/sql"
	"gorm.io/gorm"
)

// avoid unused err
var _ = InitField
var _ MonthModel = (*customMonthModel)(nil)

type (
	// MonthModel is an interface to be customized, add more methods here,
	// and implement the added methods in customMonthModel.
	MonthModel interface {
		monthModel
		customMonthLogicModel
	}

	customMonthLogicModel interface {
		WithSession(tx *gorm.DB) MonthModel
		CalcMonReport() error
		CalcLastMonReport() error
		CalcNMonReport(N int) error
		Search(ctx context.Context, limit int, offset int) ([]Dict, int32, error)
	}

	customMonthModel struct {
		*defaultMonthModel
	}
)

func (c customMonthModel) WithSession(tx *gorm.DB) MonthModel {
	newModel := *c.defaultMonthModel
	c.defaultMonthModel = &newModel
	c.conn = tx
	return c
}

func (c customMonthModel) CalcMonReport() error {
	// var ctx context.Context
	sql1 := `INSERT INTO month (money, uid, uuid, types, day, create_time)
				SELECT tmp.money, tmp.uid, tmp.uuid, tmp.types, tmp.day, tmp.create_time
				FROM (
				    SELECT
				        SUM(CASE WHEN billingtype = TRUE THEN money ELSE -money END) AS money,
				        uid,
				        uuid,
				        types,
				        STR_TO_DATE(DATE_FORMAT(create_time, '%Y-%m'), '%Y-%m') AS day,
				        NOW() AS create_time
				    FROM utxo
				    WHERE DATE_FORMAT(create_time, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m')
				    GROUP BY uid
				) AS tmp
				LEFT JOIN month ON month.day = tmp.day AND month.uid = tmp.uid
				WHERE month.day IS NULL;`
	sql2 := `UPDATE month
				JOIN (
				    SELECT
				        SUM(CASE WHEN billingtype = TRUE THEN money ELSE -money END) AS money,
				        uid,
				        uuid,
				        types,
				        STR_TO_DATE(DATE_FORMAT(create_time, '%Y-%m'), '%Y-%m') AS day,
				        NOW() AS create_time
				    FROM utxo
				    WHERE DATE_FORMAT(create_time, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m')
				    GROUP BY uid
				) AS tmp ON month.day = tmp.day AND month.uid = tmp.uid
				SET month.money = tmp.money,
				    month.uuid = tmp.uuid,
				    month.types = tmp.types,
				    month.create_time = tmp.create_time;`
	err := c.conn.Exec(sql1).Error
	fmt.Println(sql1, err)
	err = c.conn.Exec(sql2).Error
	fmt.Println(sql2, err)
	return err
}

func (c customMonthModel) CalcNMonReport(N int) error {
	// var ctx context.Context
	sql1 := `INSERT INTO month (money, uid, uuid, types, day, create_time)
				SELECT tmp.money, tmp.uid, tmp.uuid, tmp.types, tmp.day, tmp.create_time
				FROM (
				    SELECT
				        SUM(CASE WHEN billingtype = TRUE THEN money ELSE -money END) AS money,
				        uid,
				        uuid,
				        types,
				        STR_TO_DATE(DATE_FORMAT(create_time, '%Y-%m'), '%Y-%m') AS day,
				        NOW() AS create_time
				    FROM utxo
				    WHERE DATE_FORMAT(create_time, '%Y-%m') = DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL ? MONTH), '%Y-%m')
				    GROUP BY uid
				) AS tmp
				LEFT JOIN month ON month.day = tmp.day AND month.uid = tmp.uid
				WHERE month.day IS NULL;`
	sql2 := `UPDATE month
				JOIN (
				    SELECT
				        SUM(CASE WHEN billingtype = TRUE THEN money ELSE -money END) AS money,
				        uid,
				        uuid,
				        types,
				        STR_TO_DATE(DATE_FORMAT(create_time, '%Y-%m'), '%Y-%m') AS day,
				        NOW() AS create_time
				    FROM utxo
				    WHERE DATE_FORMAT(create_time, '%Y-%m') = DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL ? MONTH), '%Y-%m')
				    GROUP BY uid
				) AS tmp ON month.day = tmp.day AND month.uid = tmp.uid
				SET month.money = tmp.money,
				    month.uuid = tmp.uuid,
				    month.types = tmp.types,
				    month.create_time = tmp.create_time;`
	err := c.conn.Exec(sql1, N).Error
	fmt.Printf(sql1, N)
	fmt.Println(err)
	err = c.conn.Exec(sql2, N).Error
	fmt.Printf(sql2, N)
	fmt.Println(err)
	return err
}

func (c customMonthModel) CalcLastMonReport() error {
	return c.CalcNMonReport(1)
}

// NewMonthModel returns a model for the database table.
func NewMonthModel(conn *gorm.DB) MonthModel {
	return &customMonthModel{
		defaultMonthModel: newMonthModel(conn),
	}
}

func (m *defaultMonthModel) Search(ctx context.Context, limit int, offset int) ([]Dict, int32, error) {
	var resp []Month
	var count int64
	filter := Month{
		// Removed: false,
	}
	err := m.conn.WithContext(ctx).Model(&Month{}).Where(&filter).Count(&count).Offset(offset).Limit(limit).Find(&resp).Error

	if err == gormc.ErrNotFound {
		return nil, 0, err
	}
	ret := make([]Dict, len(resp))
	for i, item := range resp {
		ret[i] = Dict{
			"id":         item.Id,
			// "name":       item.Name,
			// "detail":     item.Detail,
			// "status":     item.Status,
			// "removed":    item.Removed,
			"createtime": item.CreateTime.Format("2006-01-02 15:04:05"),
		}
	}
	return ret, int32(count), err
}

func (m *defaultMonthModel) customCacheKeys(data *Month) []string {
	if data == nil {
		return []string{}
	}
	return []string{}
}
